home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / fileutil / fileutils-3.16.tar.gz / fileutils-3.16.tar / fileutils-3.16 / intl / l10nflist.c < prev    next >
C/C++ Source or Header  |  1996-11-27  |  10KB  |  404 lines

  1. /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
  4.  
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. License, or (at your option) any later version.
  9.  
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. Library General Public License for more details.
  14.  
  15. You should have received a copy of the GNU Library General Public
  16. License along with the GNU C Library; see the file COPYING.LIB.  If
  17. not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. Boston, MA 02111-1307, USA.  */
  19.  
  20. #ifdef HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23.  
  24. #if defined HAVE_STRING_H || defined _LIBC
  25. # ifndef _GNU_SOURCE
  26. #  define _GNU_SOURCE    1
  27. # endif
  28. # include <string.h>
  29. #else
  30. # include <strings.h>
  31. # ifndef strchr
  32. #  define strchr index
  33. # endif
  34. # ifndef memcpy
  35. #  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
  36. # endif
  37. #endif
  38.  
  39. #if defined _LIBC || defined HAVE_ARGZ_H
  40. # include <argz.h>
  41. #endif
  42. #include <ctype.h>
  43.  
  44. #if defined STDC_HEADERS || defined _LIBC
  45. # include <stdlib.h>
  46. #endif
  47.  
  48. #include "loadinfo.h"
  49.  
  50. /* On some strange systems still no definition of NULL is found.  Sigh!  */
  51. #ifndef NULL
  52. # if defined __STDC__ && __STDC__
  53. #  define NULL ((void *) 0)
  54. # else
  55. #  define NULL 0
  56. # endif
  57. #endif
  58.  
  59. /* @@ end of prolog @@ */
  60.  
  61. #ifdef _LIBC
  62. /* Rename the non ANSI C functions.  This is required by the standard
  63.    because some ANSI C functions will require linking with this object
  64.    file and the name space must not be polluted.  */
  65. # define stpcpy(dest, src) __stpcpy(dest, src)
  66. #else
  67. # ifndef HAVE_STPCPY
  68. static char *stpcpy PARAMS ((char *dest, const char *src));
  69. # endif
  70. #endif
  71.  
  72. /* Define function which are usually not available.  */
  73.  
  74. #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
  75. /* Returns the number of strings in ARGZ.  */
  76. static size_t argz_count__ PARAMS ((const char *argz, size_t len));
  77.  
  78. static size_t
  79. argz_count__ (argz, len)
  80.      const char *argz;
  81.      size_t len;
  82. {
  83.   size_t count = 0;
  84.   while (len > 0)
  85.     {
  86.       size_t part_len = strlen (argz);
  87.       argz += part_len + 1;
  88.       len -= part_len + 1;
  89.       count++;
  90.     }
  91.   return count;
  92. }
  93. # undef __argz_count
  94. # define __argz_count(argz, len) argz_count__ (argz, len)
  95. #endif    /* !_LIBC && !HAVE___ARGZ_COUNT */
  96.  
  97. #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
  98. /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
  99.    except the last into the character SEP.  */
  100. static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
  101.  
  102. static void
  103. argz_stringify__ (argz, len, sep)
  104.      char *argz;
  105.      size_t len;
  106.      int sep;
  107. {
  108.   while (len > 0)
  109.     {
  110.       size_t part_len = strlen (argz);
  111.       argz += part_len;
  112.       len -= part_len + 1;
  113.       if (len > 0)
  114.     *argz++ = sep;
  115.     }
  116. }
  117. # undef __argz_stringify
  118. # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
  119. #endif    /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
  120.  
  121. #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
  122. static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
  123.                   const char *entry));
  124.  
  125. static char *
  126. argz_next__ (argz, argz_len, entry)
  127.      char *argz;
  128.      size_t argz_len;
  129.      const char *entry;
  130. {
  131.   if (entry)
  132.     {
  133.       if (entry < argz + argz_len)
  134.         entry = strchr (entry, '\0') + 1;
  135.  
  136.       return entry >= argz + argz_len ? NULL : (char *) entry;
  137.     }
  138.   else
  139.     if (argz_len > 0)
  140.       return argz;
  141.     else
  142.       return 0;
  143. }
  144. # undef __argz_next
  145. # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
  146. #endif    /* !_LIBC && !HAVE___ARGZ_NEXT */
  147.  
  148.  
  149. /* Return number of bits set in X.  */
  150. static int pop PARAMS ((int x));
  151.  
  152. static inline int
  153. pop (x)
  154.      int x;
  155. {
  156.   /* We assume that no more than 16 bits are used.  */
  157.   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
  158.   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
  159.   x = ((x >> 4) + x) & 0x0f0f;
  160.   x = ((x >> 8) + x) & 0xff;
  161.  
  162.   return x;
  163. }
  164.  
  165.  
  166. struct loaded_l10nfile *
  167. _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
  168.             territory, codeset, normalized_codeset, modifier, special,
  169.             sponsor, revision, filename, do_allocate)
  170.      struct loaded_l10nfile **l10nfile_list;
  171.      const char *dirlist;
  172.      size_t dirlist_len;
  173.      int mask;
  174.      const char *language;
  175.      const char *territory;
  176.      const char *codeset;
  177.      const char *normalized_codeset;
  178.      const char *modifier;
  179.      const char *special;
  180.      const char *sponsor;
  181.      const char *revision;
  182.      const char *filename;
  183.      int do_allocate;
  184. {
  185.   char *abs_filename;
  186.   struct loaded_l10nfile *last = NULL;
  187.   struct loaded_l10nfile *retval;
  188.   char *cp;
  189.   size_t entries;
  190.   int cnt;
  191.  
  192.   /* Allocate room for the full file name.  */
  193.   abs_filename = (char *) malloc (dirlist_len
  194.                   + strlen (language)
  195.                   + ((mask & TERRITORY) != 0
  196.                      ? strlen (territory) + 1 : 0)
  197.                   + ((mask & XPG_CODESET) != 0
  198.                      ? strlen (codeset) + 1 : 0)
  199.                   + ((mask & XPG_NORM_CODESET) != 0
  200.                      ? strlen (normalized_codeset) + 1 : 0)
  201.                   + (((mask & XPG_MODIFIER) != 0
  202.                       || (mask & CEN_AUDIENCE) != 0) ?
  203.                      strlen (modifier) + 1 : 0)
  204.                   + ((mask & CEN_SPECIAL) != 0
  205.                      ? strlen (special) + 1 : 0)
  206.                   + ((mask & CEN_SPONSOR) != 0
  207.                      ? strlen (sponsor) + 1 : 0)
  208.                   + ((mask & CEN_REVISION) != 0
  209.                      ? strlen (revision) + 1 : 0)
  210.                   + 1 + strlen (filename) + 1);
  211.  
  212.   if (abs_filename == NULL)
  213.     return NULL;
  214.  
  215.   retval = NULL;
  216.   last = NULL;
  217.  
  218.   /* Construct file name.  */
  219.   memcpy (abs_filename, dirlist, dirlist_len);
  220.   __argz_stringify (abs_filename, dirlist_len, ':');
  221.   cp = abs_filename + (dirlist_len - 1);
  222.   *cp++ = '/';
  223.   cp = stpcpy (cp, language);
  224.  
  225.   if ((mask & TERRITORY) != 0)
  226.     {
  227.       *cp++ = '_';
  228.       cp = stpcpy (cp, territory);
  229.     }
  230.   if ((mask & XPG_CODESET) != 0)
  231.     {
  232.       *cp++ = '.';
  233.       cp = stpcpy (cp, codeset);
  234.     }
  235.   if ((mask & XPG_NORM_CODESET) != 0)
  236.     {
  237.       *cp++ = '.';
  238.       cp = stpcpy (cp, normalized_codeset);
  239.     }
  240.   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
  241.     {
  242.       /* This component can be part of both syntaces but has different
  243.      leading characters.  For CEN we use `+', else `@'.  */
  244.       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
  245.       cp = stpcpy (cp, modifier);
  246.     }
  247.   if ((mask & CEN_SPECIAL) != 0)
  248.     {
  249.       *cp++ = '+';
  250.       cp = stpcpy (cp, special);
  251.     }
  252.   if ((mask & CEN_SPONSOR) != 0)
  253.     {
  254.       *cp++ = ',';
  255.       cp = stpcpy (cp, sponsor);
  256.     }
  257.   if ((mask & CEN_REVISION) != 0)
  258.     {
  259.       *cp++ = '_';
  260.       cp = stpcpy (cp, revision);
  261.     }
  262.  
  263.   *cp++ = '/';
  264.   stpcpy (cp, filename);
  265.  
  266.   /* Look in list of already loaded domains whether it is already
  267.      available.  */
  268.   last = NULL;
  269.   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
  270.     if (retval->filename != NULL)
  271.       {
  272.     int compare = strcmp (retval->filename, abs_filename);
  273.     if (compare == 0)
  274.       /* We found it!  */
  275.       break;
  276.     if (compare < 0)
  277.       {
  278.         /* It's not in the list.  */
  279.         retval = NULL;
  280.         break;
  281.       }
  282.  
  283.     last = retval;
  284.       }
  285.  
  286.   if (retval != NULL || do_allocate == 0)
  287.     {
  288.       free (abs_filename);
  289.       return retval;
  290.     }
  291.  
  292.   retval = (struct loaded_l10nfile *)
  293.     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
  294.                 * (1 << pop (mask))
  295.                 * sizeof (struct loaded_l10nfile *)));
  296.   if (retval == NULL)
  297.     return NULL;
  298.  
  299.   retval->filename = abs_filename;
  300.   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
  301.              || ((mask & XPG_CODESET) != 0
  302.              && (mask & XPG_NORM_CODESET) != 0));
  303.   retval->data = NULL;
  304.  
  305.   if (last == NULL)
  306.     {
  307.       retval->next = *l10nfile_list;
  308.       *l10nfile_list = retval;
  309.     }
  310.   else
  311.     {
  312.       retval->next = last->next;
  313.       last->next = retval;
  314.     }
  315.  
  316.   entries = 0;
  317.   /* If the DIRLIST is a real list the RETVAL entry correcponds not to
  318.      a real file.  So we have to use the DIRLIST separation machanism
  319.      of the inner loop.  */
  320.   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
  321.   for (; cnt >= 0; --cnt)
  322.     if ((cnt & ~mask) == 0
  323.     && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
  324.     && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
  325.       {
  326.     /* Iterate over all elements of the DIRLIST.  */
  327.     char *dir = NULL;
  328.  
  329.     while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
  330.            != NULL)
  331.       retval->successor[entries++]
  332.         = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
  333.                   language, territory, codeset,
  334.                   normalized_codeset, modifier, special,
  335.                   sponsor, revision, filename, 1);
  336.       }
  337.   retval->successor[entries] = NULL;
  338.  
  339.   return retval;
  340. }
  341.  
  342. /* Normalize codeset name.  There is no standard for the codeset
  343.    names.  Normalization allows the user to use any of the common
  344.    names.  */
  345. const char *
  346. _nl_normalize_codeset (codeset, name_len)
  347.      const char *codeset;
  348.      size_t name_len;
  349. {
  350.   int len = 0;
  351.   int only_digit = 1;
  352.   char *retval;
  353.   char *wp;
  354.   size_t cnt;
  355.  
  356.   for (cnt = 0; cnt < name_len; ++cnt)
  357.     if (isalnum (codeset[cnt]))
  358.       {
  359.     ++len;
  360.  
  361.     if (isalpha (codeset[cnt]))
  362.       only_digit = 0;
  363.       }
  364.  
  365.   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
  366.  
  367.   if (retval != NULL)
  368.     {
  369.       if (only_digit)
  370.     wp = stpcpy (retval, "iso");
  371.       else
  372.     wp = retval;
  373.  
  374.       for (cnt = 0; cnt < name_len; ++cnt)
  375.     if (isalpha (codeset[cnt]))
  376.       *wp++ = tolower (codeset[cnt]);
  377.     else if (isdigit (codeset[cnt]))
  378.       *wp++ = codeset[cnt];
  379.  
  380.       *wp = '\0';
  381.     }
  382.  
  383.   return (const char *) retval;
  384. }
  385.  
  386.  
  387. /* @@ begin of epilog @@ */
  388.  
  389. /* We don't want libintl.a to depend on any other library.  So we
  390.    avoid the non-standard function stpcpy.  In GNU C Library this
  391.    function is available, though.  Also allow the symbol HAVE_STPCPY
  392.    to be defined.  */
  393. #if !_LIBC && !HAVE_STPCPY
  394. static char *
  395. stpcpy (dest, src)
  396.      char *dest;
  397.      const char *src;
  398. {
  399.   while ((*dest++ = *src++) != '\0')
  400.     /* Do nothing. */ ;
  401.   return dest - 1;
  402. }
  403. #endif
  404.